package userFileModuleApi

import (
	"KumquatDrivesServices/StorageEngine"
	"KumquatDrivesServices/common/res"
	"KumquatDrivesServices/enums"
	"KumquatDrivesServices/global"
	"KumquatDrivesServices/model"
	"KumquatDrivesServices/utils"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
	"mime/multipart"
)

type UploadChunkFileRequest struct {
	FileId     string                `form:"fileId"`
	FileName   string                `form:"fileName" binding:"required"`
	FileMd5    string                `form:"fileMd5" binding:"required"`
	FilePid    model.SnowflakeIdType `form:"filePid" binding:"required"`
	ChunkIndex int                   `form:"chunkIndex"`
	Chunks     int                   `form:"chunks"`
	ChunkFile  *multipart.FileHeader `form:"chunkFile" binding:"required"`
}

func (UserFileModuleApi) UploadFile(c *gin.Context) {
	var req UploadChunkFileRequest
	if err := c.ShouldBind(&req); err != nil {
		logrus.Error(err)
		res.FailWithCode(res.PARAM_ERR, c)
		return
	}

	userId := utils.GetUserId(c)
	var uploadId StorageEngine.EngineID
	if req.FileId == "" {
		uploadId = StorageEngine.Engine.InitiateMultipartUpload(userId)
	} else {
		uploadId = StorageEngine.EngineID(req.FileId)
	}
	var userModel model.UserModel
	userModel.ID = userId
	remainingCapacity, getCapacityErr := userModel.GetUserRemainingCapacity()
	if getCapacityErr != nil {
		logrus.Errorf("get user remaining capacity err:%v", getCapacityErr)
		res.FailWithCode(res.UPLOAD_FAIL, c)
		return
	}
	//快传
	if req.ChunkIndex == 0 {
		var userprofile model.FileModel
		if err := global.DB.Where("file_md5=? and is_folder=?", req.FileMd5, false).
			First(&userprofile).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				goto upload
			}
			res.FailWithCode(res.UPLOAD_FAIL, c)
			return
		}
		if userprofile.FileSize > remainingCapacity {
			res.FailWithCode(res.LACK_OF_SPACE, c)
			return
		}
		dbTransaction := global.DB.Begin()
		fileName, autoRenameErr := autoRename(req.FilePid, userId, req.FileName)
		if autoRenameErr != nil {
			res.FailWithCode(res.PARAM_ERR, c)
			return
		}
		file := model.FileModel{
			UserId:    userId,
			FilePid:   req.FilePid,
			FileName:  fileName,
			FileMd5:   userprofile.FileMd5,
			FileSize:  userprofile.FileSize,
			FileCover: userprofile.FileCover,
			FilePath:  userprofile.FilePath,
			FileType:  userprofile.FileType,
			IsFolder:  enums.File,
			DelFlag:   2,
		}
		if err := dbTransaction.Create(&file).Error; err != nil {
			dbTransaction.Rollback()
			res.FailWithData(res.UPLOAD_FAIL, c)
		}
		if err := userModel.UpdateUserCapacity(userprofile.FileSize, enums.AddUserCapacity); err != nil {
			logrus.Errorf("update user remaining capacity err:%v", err)
			dbTransaction.Rollback()
			res.FailWithCode(res.LACK_OF_SPACE, c)
			return
		}
		if err := dbTransaction.Commit().Error; err != nil {
			logrus.Errorf("db commit err:%v", err)
			dbTransaction.Rollback()
			res.FailWithCode(res.UPLOAD_FAIL, c)
			return
		}
		res.OkWithCode(res.INSTANT_TRANSMISSION, c)
		return
	}
upload:
	fileSize, GetTempFileSizeErr := uploadId.GetTempFileSize(userId)
	if GetTempFileSizeErr != nil {
		if errors.Is(StorageEngine.InvalidEngineIDErr, GetTempFileSizeErr) {
			res.FailWithCode(res.UPLOAD_ID_INVALID, c)
			return
		}
		logrus.Errorf("get temp file size err:%v", GetTempFileSizeErr)
		res.FailWithCode(res.UPLOAD_FAIL, c)
		return
	}
	if fileSize+req.ChunkFile.Size > remainingCapacity {
		res.FailWithCode(res.LACK_OF_SPACE, c)
		return
	}
	if err := StorageEngine.Engine.SaveTempFile(uploadId, userId, req.ChunkIndex, req.ChunkFile); err != nil {
		if errors.Is(StorageEngine.InvalidEngineIDErr, GetTempFileSizeErr) {
			res.FailWithCode(res.UPLOAD_ID_INVALID, c)
			return
		}
		logrus.Errorf("save temp file err:%v", err)
		res.FailWithCode(res.UPLOAD_FAIL, c)
		return
	}
	if req.FileId == "" {
		res.OkWithData(map[string]StorageEngine.EngineID{
			"fileId": uploadId,
		}, c)
		return
	}
	res.OkWithCode(res.SUCCESS, c)
}
